package com.exam.api.config.interceptor;

import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.exam.api.modules.system.domain.TblRole;
import com.exam.api.modules.system.vo.LoginUserInfo;
import com.exam.api.common.exception.GlobalException;
import com.exam.api.modules.system.service.TblDeptService;
import com.exam.api.modules.system.service.TblRoleService;
import com.exam.api.modules.system.service.TblUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * DataPermissionUtil
 *
 * @author bcheng
 */
@Slf4j
@Component
public class DataPermissionUtil {

    /**
     * 默认部门字段
     */
    public final static String DEFAULT_DEPT_ID = "dept_id";
    /**
     * 默认创建用户字段
     */
    public final static String DEFAULT_CREATE_USER_ID = "create_user_id";
    /**
     * 缓存
     */
    private final static TimedCache<String, Optional<DataPermission>> TIMED_CACHE = CacheUtil.newTimedCache(400);
    /**
     * 获取角色信息
     */
    private static TblRoleService tblRoleService;

    private static TblUserService tblUserService;

    /**
     * 权限查询
     *
     * @param where            查询条件
     * @param deptIdFunc       部门数据权限字段
     * @param createUserIdFunc 用户数据权限字段
     * @param <T>              实体类
     */
    public static <T> void permission(LambdaQueryChainWrapper<T> where, SFunction<T, ?> deptIdFunc, SFunction<T, ?> createUserIdFunc) {
        Optional<DataPermission> dataPermissionOpt = DataPermissionUtil.getDataPermission();
        if (dataPermissionOpt.isEmpty()) {
            return;
        }
        DataPermission dataPermission = dataPermissionOpt.get();
        // 判断是否为空
        if (CollUtil.isNotEmpty(dataPermission.deptList())) {
            where.in(deptIdFunc, dataPermission.deptList());
        }
        if (CollUtil.isNotEmpty(dataPermission.deptList()) && ObjUtil.isNotEmpty(dataPermission.userId())) {
            where.or();
        }
        if (ObjUtil.isNotEmpty(dataPermission.userId())) {
            where.eq(createUserIdFunc, dataPermission.userId());
        }
    }

    /**
     * 数据权限
     * 使用默认数据权限字段
     *
     * @param tableAlias 表别名
     * @return 数据权限
     */
    public static String permission(String tableAlias) {
        return permission(tableAlias, DEFAULT_DEPT_ID, DEFAULT_CREATE_USER_ID);
    }

    /**
     * 数据权限
     *
     * @param tableAlias         表别名
     * @param deptIdColumn       部门数据权限字段
     * @param createUserIdColumn 用户数据权限字段
     * @return 数据权限
     */
    public static String permission(String tableAlias, String deptIdColumn, String createUserIdColumn) {
        StringBuilder builder = new StringBuilder();
        Optional<DataPermission> dataPermissionOpt = DataPermissionUtil.getDataPermission();
        if (dataPermissionOpt.isEmpty()) {
            return StrUtil.EMPTY;
        }
        DataPermission dataPermission = dataPermissionOpt.get();
        if (CollUtil.isEmpty(dataPermission.deptList()) && ObjUtil.isEmpty(dataPermission.userId())) {
            return StrUtil.EMPTY;
        }
        builder.append("(");
        if (CollUtil.isNotEmpty(dataPermission.deptList())) {
            builder.append(tableAlias).append(".").append(deptIdColumn).append(" in (");
            for (Long deptId : dataPermission.deptList()) {
                builder.append(deptId).append(",");
            }
            builder.deleteCharAt(builder.length() - 1);
            builder.append(")");
        }
        if (CollUtil.isNotEmpty(dataPermission.deptList()) && ObjUtil.isNotEmpty(dataPermission.userId())) {
            builder.append(" or ");
        }
        if (ObjUtil.isNotEmpty(dataPermission.userId())) {
            builder.append(tableAlias)
                    .append(".")
                    .append(createUserIdColumn)
                    .append(" = ")
                    .append(dataPermission.userId());
        }
        builder.append(")");
        return builder.toString();
    }

    /**
     * 获取数据权限
     *
     * @return 数据权限
     */
    private static Optional<DataPermission> getDataPermission() {
        TIMED_CACHE.prune();
        if (!SpringMVCUtil.isWeb()) {
            return Optional.empty();
        }
        return Optional.ofNullable(TIMED_CACHE.get(StpUtil.getLoginIdAsString())).orElseGet(() -> {
            // 获取用户信息
            LoginUserInfo user = tblUserService.getLoginUser();
            Long deptId = user.getDeptId();
            // 获取所有角色信息
            List<TblRole> infos = tblRoleService.listRoles(user.getUserId());
            // 获取数据权限
            List<Integer> scopeTypeList = infos
                    .stream()
                    .map(TblRole::getPermissionScopeType)
                    .distinct()
                    .toList();
            // 如果数据权限存在1 跳过
            if (scopeTypeList.contains(1)) {
                Optional<DataPermission> dataPermissionOpt = Optional.empty();
                TIMED_CACHE.put(StpUtil.getLoginIdAsString(), dataPermissionOpt, 400);
                return dataPermissionOpt;
            }
            Set<Long> deptList = new HashSet<>();
            Long userId = null;
            log.debug("角色：{} 数据权限：{}", infos, scopeTypeList);
            for (TblRole info : infos) {
                Integer permissionScopeType = info.getPermissionScopeType();
            /*
              2 指定的自定义部门 数据权限
              3 当前登录人的所属部门
              4 部门以及以下
              5 进本人数据权限
             */
                switch (permissionScopeType) {
                    case 2:
                        deptList.addAll(info.getPermissionScope().getDeptIds());
                        break;
                    case 3:
                        deptList.add(deptId);
                        break;
                    case 4:
                        //本部门以及以下
                        List<Long> longs = SpringUtil.getBean(TblDeptService.class).listParentChildDeptIds(deptId);
                        List<Long> deptPer = new ArrayList<>();
                        deptPer.add(deptId);
                        if (CollUtil.isNotEmpty(longs)) {
                            deptPer.addAll(longs);
                        }
                        deptList.addAll(deptPer);
                        break;
                    case 5:
                        userId = StpUtil.getLoginIdAsLong();
                        break;
                    default:
                        throw new GlobalException("暂不支持该数据权限类型");
                }
            }
            Optional<DataPermission> dataPermissionOpt = Optional.of(new DataPermission(deptList, userId));
            TIMED_CACHE.put(StpUtil.getLoginIdAsString(), dataPermissionOpt, 400);
            return dataPermissionOpt;
        });
    }

    @Autowired
    public void setTblRoleService(TblRoleService tblRoleService) {
        DataPermissionUtil.tblRoleService = tblRoleService;
    }

    @Autowired
    public void setTblUserService(TblUserService tblUserService) {
        DataPermissionUtil.tblUserService = tblUserService;
    }

    /**
     * @param deptList 部门集合
     * @param userId   用户id
     */
    private record DataPermission(Set<Long> deptList, Long userId) {
    }
}
